

import { createRef, Fragment, useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { message } from 'antd';
import { LoadingOutlined } from '@ant-design/icons'
import { subscribe, unsubscribe } from 'pubsub-js';
import MessageItem from '../messageItem';


import {
    message_content_main,
    loading_wrapper,
    message_tips,
    message_tips_txt,
} from './index.module.css'
import { getGroupMessageContent, getGroupLastCheckTime } from '../../assets/js/api'
import { throttle } from '../../assets/js/tools'
import { getMessage, sendMessage, systemMessage } from '../../event-type';
import { useCallback } from 'react';

function MessageContent(props) {

    const { user, currentRoom } = props;

    const screen = createRef();
    const [messageInfo, setMessageInfo] = useState([]);
    const [loading, setLoading] = useState(false);
    const [noMore, setNoMore] = useState(false);
    const [atBottom, setAtBottom] = useState(true); // 当值为true则代表有新消息是将新消息至屏幕最低

    const getMessageInfo = useCallback((init = false) => {
        if (loading) return;
        setLoading(true);
        // 获取房间的消息记录
        return new Promise((resolve, reject) => {
            // useState为异步,会导致limit值不对,故在回调中调用
            const result = init ? 0 : messageInfo.length;

            // 在这里获取到的messageInfo不包括当前发送的消息
            // 意思如果发送了消息后再滚动获取之前的消息,发了多少条,就会重复获取开头的多少条

            // 因为发送或获取到了一条消息,触发了滚动事件,从而触发getMoreMessageInfo函数
            // 而新消息数目没有到messageInfo里,故messageInfo少了一条,导致limit少1
            // 而limit少1导致后端获取的时候会获取到一条消息,因为是倒叙,获取的这条消息是第一条消息,并把其返回
            // 而前端获取并赋值后,导致消息重复,会有两个第一条消息

            // 解决：将此函数变成响应式,使其更新依赖messageInfo,之后再onscroll的useEffect的依赖中添加此函数
            // 如果不再useEffect中依赖也是无效的,因为此函数在useEffect中也会闭包保持当前messageInfo
            getGroupMessageContent({
                user_id: user.id, 
                group_id: currentRoom, 
                limit: result
            })
            .then(res => {
                const {code, message: content, data} = res.data;
                if (code !== 1) {
                    setNoMore(true);
                    reject(content);
                    return;
                }
                // 数据按时间排序,将最新的数据放在数据最后一位.reverse会改变数组,所以后面不用再reverse
                resolve(data.reverse());
                setMessageInfo(val => {
                    if (!init) {
                        return [...data, ...val]
                    }
                    return [...data]
                });
            })
            .catch(err => {
                message.error({content: err});
                reject(err);
            })
            .finally(() => {
                setLoading(false);
            });
        });
    }, [messageInfo, loading, user, currentRoom]);
    const getMoreMessageInfo = useCallback((e, loading, noMore) => {
        // 往上翻加载更改消息记录
        if (noMore) {
            return;
        }
        
        const scrollHeight = e.target.scrollHeight;
        const scrollTop = e.target.scrollTop;
        if (scrollTop < 200 && !loading) {

            getMessageInfo()
            .then(data => {
                // 获取消息完成
                // 使加载完新消息后,显示的位置是加载前的位置
                e.target.scrollTop = e.target.scrollHeight - scrollHeight + scrollTop;
            })
            .catch(err => {
                console.log(err);
            });
        }
    }, [getMessageInfo]);


    useEffect(() => {
        // 更换房间时,screen的scrollTop不会变,手动将其拉到最低
        screen.current.scrollTop = screen.current.scrollHeight;
        // 切换房间初始数据请求
        if (currentRoom !== -1 && !loading) {
            setMessageInfo([]);
            setNoMore(false);
            // 获取群组的最后的部分消息
            getMessageInfo(true)
            .then(data => {
                // 获取消息完成
            })
            .catch(err => {
                console.log(err);
                message.error({content: err});
            });
        }

        window.onbeforeunload = null;
        window.onbeforeunload = function() {
            // 更新用户检查时间为离开时间
            getGroupLastCheckTime({user_id: user.id, group_id: currentRoom});
        }
    }, [currentRoom]);
    useEffect(() => {
        // 为聊天消息可视区绑定滚动事件,到顶时请求更多聊天数据
        const dom = screen.current;
        if (dom) {
            const getMore = throttle(getMoreMessageInfo, 300, loading, noMore);

            dom.onscroll = null;
            dom.onscroll = function (e) {
                const { scrollTop, clientHeight, scrollHeight } = e.target;

                if (Math.round(scrollTop) + clientHeight >= scrollHeight) {
                    setAtBottom(true);
                    return;
                } else {
                    setAtBottom(false);
                }
                if (scrollTop < 200) {
                    getMore(e);
                }
            }
        }
    }, [currentRoom, loading, noMore, screen, getMoreMessageInfo]);
    useEffect(() => {
        if (atBottom) {
            // 当atBottom时则代表用户视图需显示最新消息(最新消息在最下方)
            // 当消息是系统消息时这个会有问题,高度不对
            screen.current.scrollTop = screen.current.scrollHeight;
        }
    }, [messageInfo, atBottom, screen]);
    useEffect(() => {
        // 监听群组新信息
        const getMessageToken = subscribe(getMessage, (event, newMessage) => {
            // 添加新消息
            setMessageInfo(val => [...val, newMessage]);
        });
        const sendMessageToken = subscribe(sendMessage, (event, data) => {
            // 点击发送数据后,生成临时数据展示
            const tempMessage = {
                user_id: user.id,
                name: user.name,
                avator: user.avator,
                send_time: new Date(),
                message_id: data.message_id,
                message_content: data.msg,
                status: 'loading'
            }
            setMessageInfo(val => [...val, tempMessage]);
        });
        // 发送失败在messageItem中处理

        const systemMessageToken = subscribe(systemMessage, (event, data) => {
            if (currentRoom === 0) {
                // 设置管理员发送的系统消息,不会触发
                setMessageInfo(val => [...val, data]);
            }
        });

        return () => {
            unsubscribe(getMessageToken);
            unsubscribe(sendMessageToken);
            unsubscribe(systemMessageToken);
        }
    }, [user,currentRoom]);

    
   
    

    return (
        <div className={message_content_main} ref={screen}>
            {
                loading && !noMore ? 
                    <div className={loading_wrapper}>
                        <LoadingOutlined />
                    </div>
                    : ''
            }
            {
                noMore ? 
                    <div className={message_tips}>
                        <span className={message_tips_txt}>没有更多记录</span>
                    </div> :
                    ''
            }
            {
                messageInfo.map(item => {
                    return (
                        <Fragment key={item.message_id}>
                            <MessageItem message={item} />
                        </Fragment>
                    )
                })
            }
        </div>
    )
}




function mapStateToProps(state) {
    return {
        user: state.user,
        currentRoom: state.currentRoom
    }
}
export default connect(
    mapStateToProps,
    {

    }
)(MessageContent);


